<template>
    <div>
        <span v-if="controls" @click="increase" :class="{'is-disabled': maxDisabled}">＋</span>
        <input
          ref="input"
          type="text"
          v-bind="$attrs"
          :placeholder="placeholder"
          :min="min"
          :max="max"
          :value="displayValue"
          :disabled="inputNumberDisabled"
          @input="hanldeInput"
          @change="hanldeInputChange"
        />
        <span v-if="controls" @click="decrease" :class="{'is-disabled': minDisabled}">-</span>
    </div>
</template>

<script>
    export default {
        name: 'LeInputNumber',
        props: {
            value: {},
            placeholder: String,
            min: {
                type: Number,
                default: -Infinity
            },
            max: {
                type: Number,
                default: Infinity
            },
            precision: {
                type: Number,
                validator(val) {
                    return val >= 0 && val === parseInt(val, 10);
                }
            },
            disabled: Boolean,
            controls: {
                type: Boolean,
                default: true
            },
            step: {
                type: Number,
                default: 1
            }
        },
        data() {
            return {
                currentValue: 0,
                userInput: null
            }
        },
        computed: {
            maxDisabled() {
                // 大于最大值
                return this._increase(this.value, this.step) > this.max;
            },
            minDisabled() {
                // 小于最小值
                return this._decrease(this.value, this.step) < this.min;
            },
            displayValue() {
                if (this.userInput !== null) {
                  return this.userInput;
                }
                let currentValue = this.currentValue;
                if(typeof currentValue === 'number') {
                    if(this.precision !== undefined) {
                        currentValue = currentValue.toFixed(this.precision)
                    }
                }
                return currentValue;
            },
            inputNumberDisabled() {
                return this.disabled;
            },
            numPrecision() {
                const { value, step, getPrecision, precision } = this;
                const stepPrecision = getPrecision(step);
                if(precision !== undefined) {
                    if(stepPrecision > precision) {
                        console.warn('[Element Warn][InputNumber]precison should not be less than the decimal places of step');
                    }
                    return precision;
                }else {
                    return Math.max(getPrecision(value), stepPrecision)
                }
            }
        },
        watch: {
            value: {
                immediate: true,
                handler(value) {
                    let newVal = value === undefined ? value : Number(value);
                    if(newVal !== undefined) {
                        if(isNaN(newVal)) {
                            return;
                        }
                        if (this.precision !== undefined) {
                            newVal = this.toPrecision(newVal, this.precision);
                        }
                    }
                    if (newVal >= this.max) newVal = this.max;
                    if (newVal <= this.min) newVal = this.min;
                    this.currentValue = newVal;
                    this.userInput = null;
                    this.$emit('input', newVal);
                }
            }
        },
        methods: {
            _increase(val,step) {
                if(typeof val !== 'number' && val !== undefined) return this.currentValue;
                const precisionFactor = Math.pow(10, this.numPrecision);
                return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor)
            },
            _decrease(val, step) {
                if(typeof val !== 'number' && val !== undefined) return this.currentValue;
                const precisionFactor = Math.pow(10, this.numPrecision);
                return this.toPrecision((precisionFactor * val - precisionFactor * step) / precisionFactor)
            },
            increase() {
                if(this.inputNumberDisabled || this.maxDisabled) return;
                const value = this.value || 0;
                const newVal = this._increase(value, this.step);
                this.setCurrentValue(newVal);
            },
            decrease() {
                if(this.inputNumberDisabled || this.minDisabled) return;
                const value = this.value || 0;
                const newVal = this._decrease(value, this.step);
                this.setCurrentValue(newVal);
            },
            hanldeInput(e) {
                this.userInput = e.target.value;
            },
            toPrecision(num, precision) {
                if(precision === undefined) precision = this.numPrecision;
                 return parseFloat(Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision));
            },
            getPrecision(value) {
                if(value === undefined) return 0;
                const valueString = value.toString(); 
                const dotPosition = valueString.indexOf('.');  
                let precision = 0;
                if(dotPosition !== -1) {
                    precision = valueString.length - dotPosition - 1;
                }
                return precision;
            },
            setCurrentValue(newVal) {
                const oldVal = this.currentValue;
                if(typeof newVal === 'number' && this.precision !== undefined) {
                    newVal = this.toPrecision(newVal, this.precision);
                }
                if(newVal >= this.max) newVal = this.max;
                if(newVal <= this.min) newVal = this.min;
                if(oldVal === newVal) return;
                this.userInput = null;
                this.$emit('input', newVal);
                this.$emit('change', newVal, oldVal);
                this.currentValue = newVal;
            },
            hanldeInputChange(value) {
                const newVal = value === '' ? undefined : Number(value);
                if(!isNaN(newVal) || value === '') {
                    this.setCurrentValue(newVal);
                }
                this.userInput = null;
            }
        }
    }
</script>

<style lang="scss" scoped>

</style>